﻿using System;
using System.Collections.Generic;
using System.Numerics;

namespace AppMain
{
    public class Physics
    {

        public static bool cast3D(Box3D p1, Box3D p2)
        {
            return !(p2.zMax <= p1.zMin || p2.zMin >= p1.zMax || p2.xMin >= p1.xMax || p2.xMax <= p1.xMin
          || p2.yMax <= p1.yMin || p2.yMin >= p1.yMax);
        }

        public static bool cast2D(Box2D p1, Box2D p2)
        {
            return !(p2.zMax <= p1.zMin || p2.zMin >= p1.zMax || p2.xMin >= p1.xMax || p2.xMax <= p1.xMin);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="roleBox"></param> 玩家碰撞盒
        /// <param name="segmentArray"></param> 场景中的线段
        /// <param name="xMove"></param>x轴移动距离
        /// <param name="zMove"></param>y轴移动距离
        static public Vec2 moveCast(Box3D roleBox, Segment[] segmentArray, float xMove, float zMove, float percent = 1)
        {
            if (segmentArray == null)
                return Vec2.zero; ;
            if (percent < 0.1f)
                return Vec2.zero; ;
            xMove *= percent;
            zMove *= percent;

            float posX = roleBox.posX;
            float posZ = roleBox.posZ;
            float sizeX = roleBox.sizeX;
            float sizeZ = roleBox.sizeZ;

            float moveBoxPosX = xMove + posX;// (xMove + posX + posX) * 0.5f;
            float moveBoxPosZ = zMove + posZ;// //(zMove + posZ + posZ) * 0.5f;
            float moveBoxSizeX = sizeX;
            float moveBoxSizeZ = sizeZ;

            float xMoveAbs = Math.Abs(xMove);
            if (xMoveAbs > sizeX)
            {
                moveBoxSizeX = xMoveAbs;
                if (xMoveAbs > 0)
                {
                    moveBoxPosX = (sizeX + xMove) * 0.5f + posX;
                }
                else
                {
                    moveBoxPosX = (xMove - sizeX) * 0.5f + posX;
                }
            }
            float zMoveAbs = Math.Abs(zMove);
            if (zMoveAbs > sizeZ)
            {
                moveBoxSizeZ = zMoveAbs;
                if (zMoveAbs > 0)
                {
                    moveBoxPosZ = (sizeZ + zMove) * 0.5f + posZ;
                }
                else
                {
                    moveBoxPosZ = (zMove - sizeZ) * 0.5f + posZ;
                }
            }
            Box2D moveBox = new Box2D(moveBoxSizeX, moveBoxSizeZ, moveBoxPosX, moveBoxPosZ);

            for (int i = 0; i < segmentArray.Length; i++)
            {
                float xMin = moveBox.xMin;
                float xMax = moveBox.xMax;
                float zMin = moveBox.zMin;
                float zMax = moveBox.zMax;

                //1.矩形与线段矩形相交检测
                Segment segment = segmentArray[i];
                if ((segment.startZ > zMax && segment.endZ > zMax) ||
                    (segment.startZ < zMin && segment.endZ < zMin) ||
                    (segment.startX > xMax && segment.endX > xMax) ||
                    (segment.startX < xMin && segment.endX < xMin)
                    )
                {
                    continue;
                }
                //2.矩形与线段相交检测
                //如果有一条线段与BOX相交 则二分法查找下个
                Vector2 segStart = new Vector2(segment.startX, segment.startZ);
                Vector2 segEnd = new Vector2(segment.endX, segment.endZ);
                Vector2 segVector = segStart - segEnd;
                Vector2 segToBox1 = segStart - new Vector2(xMax, zMax);
                Vector2 segToBox2 = segStart - new Vector2(xMin, zMax);
                Vector2 segToBox3 = segStart - new Vector2(xMin, zMin);
                Vector2 segToBox4 = segStart - new Vector2(xMax, zMin);

                float c1 = CrossProduct(segVector, segToBox1);
                float c2 = CrossProduct(segVector, segToBox2);
                float c3 = CrossProduct(segVector, segToBox3);
                float c4 = CrossProduct(segVector, segToBox4);

                if (c1 >= 0 && c2 >= 0 && c3 >= 0 && c4 >= 0)
                {
                    continue;
                }
                if (c1 <= 0 && c2 <= 0 && c3 <= 0 && c4 <= 0)
                {
                    continue;
                }
                percent *= 0.8f;
                return moveCast(roleBox, segmentArray, xMove, zMove, percent);
            }
            return new Vec2(xMove, zMove);
        }

        static private float CrossProduct(Vector2 v1, Vector2 v2)
        {
            return v1.X * v2.Y - v1.Y * v2.X;
        }

        public static float getDistance(Box3D a, Box3D b)
        {
            float diff_x = a.posX - b.posX;
            //float diff_y = a.posY - b.posY;
            float diff_z = a.posZ - b.posZ;
            return (float)Math.Sqrt(diff_x * diff_x + diff_z * diff_z);
        }
    }

}

